package joney.bonjour;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import joney.main.utils.JoneyUtil;
import joney.model.DataModel;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;

import com.apple.dnssd.DNSSD;
import com.apple.dnssd.DNSSDException;
import com.apple.dnssd.DNSSDRegistration;
import com.apple.dnssd.DNSSDService;
import com.apple.dnssd.RegisterListener;

public class BonjourServer implements RegisterListener{

	public static final String serviceProtocol = "_money._tcp";
	public static final String serviceName = "iMoney";
	
	public static final int BUFFER_SIZE= 1024;
	
	private ServerSocket serverSok=null;
	private DNSSDService service= null;
	
	private IProgressMonitor monitor;
	private MessageHandler messageHandler;
	
	
	public BonjourServer(IProgressMonitor monitor )
	{
		this.monitor= monitor;
		
		try {
			serverSok = new ServerSocket(0, 0, InetAddress.getLocalHost());
		} catch (IOException e) {
			error(e);
		}
	}
	
	
	public boolean startRegisterService()
	{
		if(serverSok == null){return false;}
		
		monitor.beginTask("registering Bonjour service", 0);
		
		try {
			service = DNSSD.register(serviceName, serviceProtocol, serverSok.getLocalPort(), this);
		} catch (DNSSDException e) {
			error(e);
			return false;
		}
		
		return true;
	}
	
	public boolean stopRegisterService()
	{
		if(service != null){
			service.stop();
		
			monitor.setCanceled(true);
		
			
			if(messageHandler != null)
				messageHandler.stop();
			
			try {
				serverSok.close();
			} catch (IOException e) {
				error(e);
			}
			
			return true;
		}
	
		return false;
	}


	public void serviceRegistered(DNSSDRegistration registration, int flags,
		    String serviceName, String regType, String domain) {
		
		monitor.setTaskName("Device Registered");
		new Thread(messageHandler= new MessageHandler()).start();
	}


	public void operationFailed(DNSSDService service, int errorCode) {
		error(new Exception("Error registering service: " + errorCode));
	}
	
	
	private void error(Exception e)
	{
		e.printStackTrace();
		
	}
	
	
	private class MessageHandler implements Runnable
	{
		private Socket socket;
		private DataInputStream din;
		private DataOutputStream dout;
		private boolean running = false;
		

		public void run() {
			
			monitor.setTaskName("Connecting to Device");
			try {
				socket = serverSok.accept();
			} catch (IOException e) {
				System.out.println(e);
				return;
			}
			
			
			monitor.setTaskName("Connected to " + socket);
			
			running= true;
			
			if(socket != null){
			try {
				din = new DataInputStream(socket.getInputStream());
				dout = new DataOutputStream(socket.getOutputStream());
			} catch (IOException e) {
			}
			}
			else
				return;
			
			byte[] buffer = new byte[BUFFER_SIZE];
			int bytesRead = 0;
			
			//TODO send data rec data etc
			monitor.setTaskName("Waiting for Data");
			try {
				bytesRead = din.read(buffer);
				
				} catch (IOException e) {
					e.printStackTrace();
			}
				
			monitor.setTaskName("Received Data from device");	
				
			
			try {
			byte newBuffer[] = new byte[bytesRead];
			System.arraycopy(buffer, 0, newBuffer, 0, bytesRead);
			final String xmlString = new String(newBuffer, "UTF8");
			
			System.out.println(xmlString.length() + " "  + xmlString);
			
			
			JoneyUtil.getDisplay().asyncExec(new Runnable()
			{
				public void run() {
					//import data into table
					DataModel.importData(xmlString.trim());
					
					monitor.setTaskName("Sending Data Back");
					String s = DataModel.getXML();
					//System.out.println("message size: " + s.length());
					try {
						dout.write(s.getBytes());
					} catch (IOException e) {
						e.printStackTrace();
						monitor.setTaskName("error sending data " + e.toString());	
						monitor.done();
						return;
					}
				}
				
			});
			
			
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			
			
			
			
			buffer = new byte[BUFFER_SIZE];
			monitor.setTaskName("Waiting for Sync Done");
			try {
				din.read(buffer);
				} catch (IOException e) {
					e.printStackTrace();
			}
			
//			try {
//				System.out.println(new String(buffer, "UTF8"));
//			} catch (UnsupportedEncodingException e) {
//				e.printStackTrace();
//			}	
				
			
			monitor.setTaskName("Done");		
			monitor.done();
				
			JoneyUtil.getDisplay().asyncExec(new Runnable()
			{
				public void run() {
					IWorkbenchPage wbp = PlatformUI.getWorkbench().
					getActiveWorkbenchWindow().getActivePage();

					IViewPart ivp = wbp.findView("joney.devicesyncview");
					wbp.hideView(ivp);
				}
			});
			
			
			if(service != null){
				service.stop();
			}
			
		}
		
		public void stop()
		{
			running = true;
		}
		
	}
	
}
